A struct in C programming language is a structured (record) type[1] that aggregates a fixed set of labelled objects, possibly of different types, into a single object.
A struct
declaration consists of a list of fields, each of which can have any type. The total storage required for a struct object is the sum of the storage requirements of all the fields, plus any internal padding.
For example:
struct account { int account_number; char *first_name; char *last_name; float balance; };
defines a type, referred to as struct account. To create a new variable of this type, we can write
struct account s;
which has an integer component, accessed by s.account_number, and a floating-point component, accessed by s.balance, as well as the first_name and last_name components. The structure s contains all four values, and all four fields may be changed independently.
The primary use of a struct is for the construction of complex datatypes, but in practice they are sometimes used to circumvent standard C conventions to create a kind of primitive subtyping. For example, common Internet protocols rely on the fact that C compilers insert padding between struct fields in predictable ways; thus the code
struct ifoo_version_42 { long x, y, z; char *name; long a, b, c; }; struct ifoo_old_stub { long x, y; }; void operate_on_ifoo(struct ifoo_version_42 *); struct ifoo_old_stub s; . . . operate_on_ifoo(&s);
is often assumed to work as expected, if the operate_on_ifoo function only accesses fields x and y of its argument.
Contents |
There are two ways to initialize a structure. The C89-style initializers are used when contiguous members may be given.[2]
/* Define a type point to be a struct with integer members x, y */ typedef struct { int x; int y; } point; /* Define a variable p of type point, and initialize all its members inline! */ point p = {1,2};
For non contiguous or out of order members list designated initializer style [3] may be used
/* Define a variable p of type point, and set members using designated initializers*/ point p = {.y = 2, .x = 1};
Omitted elements are initialised to 0. The disadvantage of designated initializer style is that this feature is not defined for C++ programming language, according to C++11 standard [4]
The following assignment of a struct to another struct does what one might expect. It is not necessary to use memcpy()
to make a duplicate of a struct type. The memory is already given and zeroed by just declaring a variable of that type regardless of member initialization. This should not be confused with the requirement of memory management when dealing with a pointer to a struct.
#include <stdio.h> /* Define a type point to be a struct with integer members x, y */ typedef struct { int x; int y; } point; int main(int argc, char * argv[]) { /* Define a variable p of type point, and initialize all its members inline! */ point p = {1,2}; /* Define a variable q of type point. Members are initialized with the defaults for their derivative types such as 0. */ point q; /* Assign the value of p to q, copies the member values from p into q. */ q = p; /* Change the member x of q to have the value of 2 */ q.x = 2; /* Demonstrate we have a copy and that they are now different. */ if (p.x != q.x) printf("The members are not equal! %d != %d", p.x, q.x); }
Pointers can be used to refer to a struct by its address. This is particularly useful for passing structs to a function by reference. The pointer can be dereferenced just like any other pointer in C — using the * operator. There is also a -> operator in C which dereferences the pointer to struct (left operand) and then accesses the value of a member of the struct (right operand).
struct point { int x; int y; } my_point; struct point *p = &my_point; /* To declare p as a pointer of type struct point */ (*p).x = 8; /* To access the first member of the struct */ p->x = 8; /* Another way to access the first member of the struct */
Typedefs can be used as shortcuts, for example:
typedef struct account { int account_number; char *first_name; char *last_name; float balance; } account;
Different users have differing preferences; proponents usually claim:
Without typedef:
struct point { int x; int y; }; typedef struct point *(*point_compare_t) (struct point *a, struct point *b);
With typedef:
struct point { int x; int y; }; typedef struct point point_t; typedef point_t *(*point_compare_t) (point_t *a, point_t *b);
If neither typedef were used in defining a function that takes a pointer to a type of the above function pointer, the following code would have to be used. Although valid, it becomes increasingly hard to read quickly.
/* Define our struct point type */ struct point { int x; int y; }; /* Define a function that returns a pointer to the biggest point, using a function to do the comparison. */ struct point *biggest_point (size_t size, struct point *points, struct point *(*point_compare) (struct point *a, struct point *b)) { int i; struct point *biggest = NULL; for (i=0; i < size; i++) { biggest = point_compare(biggest, points + i); } return biggest; }
However, there are a handful of disadvantages in using them:
account.balance
)
/* Example for namespace clash */ typedef struct account { float balance; } account; struct account account; /* possible */ account account; /* error */